<template>
  <div class="task-main page-main" v-title data-title="甘特图">
    <home-nav :userData="userinfo"></home-nav>
    <div class="container">
      <div class="head-content">
        <span class="bold-font">{{projectNo}}&nbsp;&nbsp;{{projectName}}</span> 
        <div>
          <span v-for="item of navlist" :key="item.val" :class="['nav', { 'active': navId==item.val }]" @click="handChange(item)">{{item.name}}</span>
        </div>       
      </div>
      <div class="content">
        <div v-show="navId == '1'">
          <TimeListShowIn
            :projectId="projectId"
            :projectManager="projectManager"
            :projectClass="projectClass"
            :status="status"
            :projectAll="projectAll"
            :projectReport="projectReport"
            :timeListData="timeListData"
          ></TimeListShowIn>
        </div>
        <div v-show="navId == '2'">
          <div class="radio-group">
            <a-button class="button-span" type="primary" @click="exportToPDF">导出pdf</a-button>
            <div class="radio-span">
              <span><i class="green-line"></i>按时完成</span>
              <span><i class="purple-line"></i>提前完成</span>
              <span><i class="red-line"></i>逾期完成</span>
              <span><i class="blue-line"></i>进行中</span>
            </div>
            <a-radio-group v-model="radioId" button-style="solid" @change="handChangeRadio">
              <a-radio-button value="d">日</a-radio-button>
              <a-radio-button value="m">月</a-radio-button>
            </a-radio-group>
          </div>
          <div ref="gantt" class="gantt-content"/>
        </div>
      </div>
    </div>
    <a-back-top class="backtodom" /> 
  </div>
</template>

<script>
import {getAction} from '@/api/manage'
import {gantt} from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import '@/utils/dhtmlxgantt.api.js'
import cloneDeep from 'lodash/cloneDeep'
import moment from 'moment'
import { getOneArr } from '@/utils/util'

export default {
  name: 'ProjectGantt',
  mixins:[],
  components: {
    HomeNav: () => import('@/components/layouts/HomeNav'),
    TimeListShowIn: () => import('@/components/tools/timeListShowIn'),
  },
  data() {
    return{
      userinfo: {
        info: this.$store.getters.userInfo,
        module: 'projectGantt',
      },
      navId: '2',
      navlist: [
        {name: '甘特图', val: '2'},
        {name: '细项', val: '1'},
      ],
      radioId: 'm',
      projectAll: this.$route.query.pa,
      projectManager: this.$route.query.pm,
      projectClass: this.$route.query.pc,
      status: this.$route.query.status,
      projectReport: this.$route.query.pr,
      projectId: this.$route.query.id,
      projectNo: this.$route.query.no,
      projectName: this.$route.query.name,
      timeListData: [],
      url: {
        queryListByBuildId: '/projectBuildTime/queryListByBuildId',
      },
      dataSource: [],
      tasks: {
        data: [],        
        links: [
           // type1: 开头到开头   0结尾到开头  2结尾到结尾 3开头到结尾
          // { id: '10', source: '11', target: '12', type: '1' },
          // { id: '11', source: '12', target: '13', type: '0' },
          // { id: '12', source: '13', target: '14', type: '2' },
        ],
      },
    }
  },
  mounted () {   
    this.doGetTimeData(this.projectId)
    if (this.projectClass == '60') {
      this.navId = '1'
    }
  },
  methods: {
    doGetTimeData(id) {
      if (id) {
        getAction(this.url.queryListByBuildId, { projectBuildId: id }).then((res) => {          
          // 细项
          res.result.forEach((item) => { 
            item.children = item.childrens          
            item.childrens.forEach((subItem) => {
              if (subItem.reportStatus == 2) {
                subItem.colorBg = 'color-suc'
              } else {
                subItem.colorBg = 'color-dis'
              }
            })                        
          }) 
          this.timeListData = res.result || []                                       
          // 甘特图
          const result = cloneDeep(res.result || [])
          const gt = getOneArr(result, 'childrens')
          this.tasks.data = this.setGanttData(gt)                     
          this.init(this)
        })
      }
    },
    setGanttData(list){
      list.forEach(item=>{
        if(item.parentCode !=  "-1"){                           
          item.parent = item.parentCode
        }
        item.id = item.timeNodeCode
        item.text = item.timeNode                        
        item.reportName = item.addReportUserName || this.projectManager // 报工人        
        // 计算间隔
        let startDate = item.status === 1 ? item.planStartDate : item.planStartDateAudit // 计划开始
        let endDate = item.status === 1 ? item.completionDate : item.completionDateAudit // 计划完成
        let comendDate;
        if(startDate){          
          startDate =  moment(startDate).format('YYYY-MM-DD'); 
        }        
        if(endDate) {
          endDate = moment(endDate).format('YYYY-MM-DD'); 
        } 
        if(item.realCompletionDate){
          comendDate = moment(item.realCompletionDate).format('YYYY-MM-DD'); // 实际完成          
        }
        // 计算进度                         
        const d = moment(endDate).diff(startDate, 'days') // 计划开始-》计划结束
        const comd = moment(comendDate).diff(startDate, 'days') // 计划开始-》实际结束        
        const isBefore= moment(comendDate).isBefore(endDate) // true按时或提前完成  false超时        
        if(!item.children || item.children.length == 0){
          // 时长
          if(comendDate){
            if(isBefore){
              item.duration = endDate && startDate ? d + 1 : 0  // 正常完成，以计划结束为end            
            }else{
              item.duration = comendDate && startDate ? comd + 1 : 0  // 延误完成，以实际结束为end
            }
          }else{
            item.duration = endDate && startDate ? d + 1 : 0  // 未完成，以计划结束为end 
          }
                    
          // 已完成才有进度显示
          if(item.realCompletionDate){            
            if(isBefore){
              item.progress = ((comd+1) / (d+1)).toFixed(2)
            }else{
              item.progress = ((d+1) / (comd+1)).toFixed(2)
            }            
          }
          // 实际结束 < 计划开始
          if(comendDate && startDate && moment(comendDate).isBefore(startDate)){                         
            const x = moment(endDate).diff(comendDate, 'days')  // 实际结束-》计划结束
            const xx = moment(startDate).diff(comendDate, 'days') // 实际结束-》计划开始
            item.duration = x + 1 || 0
            item.progress = (xx / (x+1)).toFixed(2)
          }
        }else{
          const l = item.children.filter(j =>{
            return j.reportStatus == '2'
          })
          item.progress = (l.length / item.children.length).toFixed(2)
        }
        item.start_date = startDate
        if(comendDate && startDate && moment(comendDate).isBefore(startDate)){ // 实际完成 < 计划开始
          item.start_date = comendDate
        }
        item.start_date_PLAN = startDate
        item.end_date_PLAN = endDate      
        item.open = true
      })
      return list
    },
    // 初始化
    init(e) {
      gantt.clearAll()
      gantt.i18n.setLocale('cn')      
      gantt.config.autosize = false; // 自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
      gantt.config.fit_tasks = true    // 自动延长时间刻度  
      gantt.config.readonly = true // 只读模式
      gantt.config.autofit = true  // 图表宽度自适应
      gantt.config.smart_scales = true // 仅仅渲染在屏幕可见的那部分时间轴    
      gantt.config.smart_rendering = true // 按需渲染, 仅仅渲染在屏幕可见的那部分任务和依赖线        
      gantt.config.details_on_dblclick = false;	// 禁用双击事件
      gantt.config.show_errors = false; // 关闭所有错误提示信息：gantt有自己的异常消息，如果不关闭可能页面会弹出异常消息      
      gantt.config.date_format = '%Y年-%n月-%d日';       
      gantt.config.row_height = 40; // 设置行高      
      gantt.config.scale_height = 65; // 表头高度
      gantt.config.min_column_width = 50;            
      
      this.handChangeRadio() // 按日/月区分
      // 悬浮框            
      gantt.plugins({ tooltip: true, marker: true  }); 
      gantt.templates.tooltip_text = function(start,end,task){        
        let html = `
          <div style="display:flex"><b>主要完成内容：</b><span style="display: inline-block;max-width: 600px;white-space: pre-line;">${task.jobContent || ''}</span></div>
          <b>计划开始时间：</b>${task.start_date_PLAN || ''}<br/>
          <b>计划完成时间：</b>${task.end_date_PLAN || ''}<br/>              
        `
        if(task.realCompletionDate){
          html += `
            <b>实际完成时间：</b>${task.realCompletionDate || ''}<br/>              
          `
          if(!moment(task.realCompletionDate).isBefore(task.start_date_PLAN)){
            html += `<b>报工时长：</b>${task.duration}天<br/>`
          }          
        }else{
          html += `
            <b>预计时长：</b>${task.duration}天<br/>  
          `
        }
        if(task.parentCode != "-1"){
          html += `<b>当前状态：</b>${task.reportStatus == '2' ? '已完成' : '未完成'}<br/>`
        }else{
          html += `<b>当前状态：</b>${task.realCompletionDate ? '已完成' : '未完成'}<br/>`
        }
        if(task.delayReason){
          html += `<div style="display:flex"><b>延误原因：</b><span style="display: inline-block;max-width: 600px;white-space: pre-line;">${task.delayReason || ''}</span></div><br/>`          
        }
        return html                
      };      
      // 文本
      gantt.templates.progress_text = function (start, end, task) {                        
        // 只有父类才显示进度
        if(task.parentCode == '-1' && e.radioId == 'd'){
          return task.realCompletionDate ? '100%' : (task.progress * 100 + '%')      
        }else{
          return  ''
        }        
      };      
      gantt.templates.rightside_text = function (start, end, task) {        
        return e.getTaskFitValue(task) === 'right' ? task.text : ''
      }
      gantt.templates.task_text = function (start, end, task) {
        return e.getTaskFitValue(task) === 'center' ? task.text : ''
      }
      // task 自定义样式
      gantt.templates.task_class = function (start, end, task) {   
        // start_date_PLAN 计划开始时间 planStartDate / planStartDateAudit
        // end_date_PLAN 计划完成时间 completionDate / completionDateAudit
        // 实际完成时间 realCompletionDate
        /**
         * 【计划开始时间】到【实际完成时间】如果没有逾期显示绿色；
         *  如果比计划提前完成，【实际完成时间】到【计划完成时间】显示灰色。
         *  如果有逾期的，【计划完成时间】到【实际完成时间】显示红色。
         *  moment(endDate).diff(startDate, 'days')
         */
        
        const today =  moment(new Date()).format('YYYY-MM-DD')    // 今天
        const { end_date_PLAN, realCompletionDate} = task
        let c = 'project_timeline'         
        if(realCompletionDate && moment(realCompletionDate).diff(end_date_PLAN, 'days') > 0){
          c = 'project_timeline_red' // 逾期已完成
        }
        if(!realCompletionDate && moment(today).diff(end_date_PLAN, 'days') > 0){
          c = 'project_timeline_red' // 逾期未完成
        }
        if(realCompletionDate && moment(realCompletionDate).diff(end_date_PLAN, 'days') < 0){
          c = 'project_timeline_grey' // 提前完成
        }      
        return c
      };      
      // 配置左侧表格项
      gantt.config.columns = [        
        { name: "text", tree: true, width: 170, label: "项目关键节点", resize: true, align: 'left', },        
        { name: "reportName", width: 120, label:"负责人", resize: true, align: 'center'},
        { name: "start_date_PLAN", width: 100, label:"计划开始时间", resize: true, align: 'center'},
        { name: "end_date_PLAN", width: 100, label:"计划完成时间", resize: true, align: 'center'},        
      ]                    
      const date = new Date() // 今日竖线    
      gantt.addMarker({
          start_date: date,
          text: "今日：" + moment(date).format('YYYY-MM-DD')
      });     
      gantt.init(this.$refs.gantt) // 初始化
      gantt.parse(this.tasks) // 数据解析            
    },
    getTaskFitValue(task) {
      const font_width_ratio = 12
      const taskStartPos = gantt.posFromDate(task.start_date)
      const taskEndPos = gantt.posFromDate(task.end_date)
      const width = taskEndPos - taskStartPos
      const str = task.text
      const len = task.parentCode == '-1' ? str.length + 6 : str.length
      const textWidth = len * font_width_ratio

      if(this.radioId == 'm' && task.progress){
        const s = moment(task.start_date).format('YYYY-MM')
        const e = moment(task.end_date).format('YYYY-MM')
        if(moment(e).diff(s, 'days') <= 62){
          return 'right'
        }
      }
      if (width < textWidth) {
        return 'right'
      } else {
        return 'center'
      }
    },
    exportToPDF(){
      gantt.exportToPDF({
        name: `${this.projectNo}甘特图.pdf`,        
        raw:true
      });
    },

    /**
     * 操作 
     * 
     */
    handChange(item){
      if(this.navId != item.val){
        this.navId = item.val
      }      
    },
    handChangeRadio(){
      if(this.radioId == 'm'){     
        // 按月区分
        gantt.config.scales = [
          {unit: "year", step: 1, format: "%Y年"},
          {unit: "month", step: 1, format: "%n月"},
        ];
        // 周末颜色区分
        // gantt.templates.timeline_cell_class = function(item, date){
        //   return "";
        // };
      }else{
        // 按日区分        
        gantt.config.scales = [
          {unit: "month", step: 1, format: "%Y年%M"},
          {unit: "day", step: 1, format: "%j"},
          {unit: "day", step: 1, format: "%D", css: function(date) {
            if(!gantt.isWorkTime({ date: date, unit: "day"})){
                  return "weekend"
              }
            }
          }
        ];
        // 周末颜色区分
        // gantt.templates.timeline_cell_class = function(item, date){
        //   if(date.getDay()== 0 || date.getDay()== 6){
        //     return "weekend";
        //   }
        // };         
      }
      gantt.refreshData();
    },
  }
}
</script>
<style lang="less" scoped>
@import '~@assets/less/hte-main.less';
.gantt-content{height: 680px;}
/deep/ .gantt_tooltip{max-width: 700px;}
.head-content{position: relative;justify-content: center;font-size: 18px;color: #303133;
  .bold-font{position: absolute;left: 24px;top: 16px;max-width: 36%;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;
    &:before{display: none !important;}
  }
  .nav{position: relative;padding: 0 15px;cursor: pointer;margin: 0 10px;
    &:after{content: '';position: absolute;bottom: -18px;left: 0;width: 100%;height: 2px;}
    &.active{color: #489BD2;
      &:after{background-color: #489BD2;}
    }
    &:hover{color: #489BD2;}
  }
}
.content{padding: 13px 24px;background-color: #fff;
  .radio-group{
    display: flex;
    justify-content: center;
    align-content: center;
    margin-bottom: 10px;
    position: relative;
    .button-span{position: absolute;left: 0;top: 0;background-color: #489BD2;}
    .radio-span{
      position: absolute;
      right: 0px;
      top: 7px;
      max-width: 333px;
      overflow: hidden;
      font-size: 14px;
      color: #333;
      font-weight: 600;
      span{margin-left: 13px;}
      i{width:11px;height:5px;display:inline-block;margin-right:3px;vertical-align: middle;margin-top:-2px;
        &.green-line{background-color: #67C23A;}
        &.purple-line{background-color: #ae81ff;}
        &.red-line{background-color: #F9A7A7;}
        &.blue-line{background-color: #8CC5FF;}
      }      
    }
  }
  .ant-radio-group-solid .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){
    background: #489BD2;
    border-color: #489BD2;
  }
}
</style>
